<script setup lang="ts">
import moment from 'moment'
import { usePlayerStore } from '@/stores/playerStore'
import MyProgress from './progress.vue'
import PlayController from './play-controller.vue'
import useSyncWrapperTransform from '@/components/player/hooks/use-sync-cd-wrapper-transform'
import playlist from '@/components/playlist/index.vue'
import { PLAY_MODE } from '@/enum'
import type { SwipeInstance } from 'vant'
import Scroll from '@/components/scroll/index.vue'
import MiniPlayer from '@/components/mini-player/index.vue'
import useIsExceed from '@/common/use-is-exceed'
import useLyric from '@/components/player/hooks/use-lyric'
import { px2vmin } from '@/utils'
import MusicList from '@/components/music-list/index.vue'
import { showToast } from 'vant'
import { __BOTTOM_BAR_HEIGHT__ } from '@/utils/constant'
const playerStore = usePlayerStore()
const currentSong = computed<ISongItem | undefined>(() => {
  return playerStore.playlist[playerStore.currentIndex]
})
const showPlayList = ref<boolean>(false)
const currentTime = ref<number>(0)
const sliderValue = ref<number>(0)
const audioRef = ref<HTMLAudioElement | null>(null)
const canPlay = ref<boolean>(false)
const showCdWrapper = ref<boolean>(true)
const lyricScrollRef = ref<InstanceType<typeof Scroll> | null>(null)
const lyricContainerRef = ref<HTMLUListElement | null>(null)
const progressRef = ref<InstanceType<typeof MyProgress>>()
const showMusicListCom = ref<boolean>(false)
const songList = ref<ISongItem[]>([])
const singerName = ref<string>('')
const singerPic = ref<string>('')
const loading = ref<boolean>(false)
// 同步cd唱片滚动
useSyncWrapperTransform('.player .cd', '.player .cd-pic')
const middleHeight = ref<number>(0)
watch(
  () => playerStore.fullScreen,
  async (newVal: boolean) => {
    await nextTick()
    if (newVal) {
      let height: number = 0
      const classNames = [
        '.player .header',
        '.player .singer-name',
        '.play-controller',
        '.progress'
      ]
      classNames.forEach((className: string) => {
        height += document.querySelector(className)?.clientHeight || 0
      })
      middleHeight.value = window.innerHeight - height - __BOTTOM_BAR_HEIGHT__
      swipeRef.value?.resize()
      swipeRef.value?.swipeTo(playerStore.currentIndex)
    }
  }
)
// 标题是否超过父元素
const { isExceed } = useIsExceed('.player .header .title', '.player .header .title .text')
watch(currentSong, async (newSong: ISongItem | undefined, prevSong: ISongItem | undefined) => {
  if (prevSong && newSong && prevSong.id === newSong.id) {
    return
  }
  await nextTick()
  pauseLyric()
  canPlay.value = false
  currentTime.value = 0
  // swiper滚动到对应的位置
  swiperTo()
  const audioRefVal = audioRef.value
  if (newSong) {
    if (typeof newSong.rtUrl === 'string') {
      if (audioRefVal) {
        audioRefVal.currentTime = currentTime.value = 0
        audioRefVal.src = newSong.rtUrl
        if (!playerStore.playing) {
          playerStore.playing = true
        }
      }
    }
  }
})
watch(
  () => playerStore.playing,
  (newPlayStatus: boolean) => {
    pauseMusic()
    const audioRefVal = audioRef.value
    if (newPlayStatus) {
      if (canPlay.value) {
        if (audioRefVal) {
          audioRefVal.play()
          audioRefVal.currentTime = currentTime.value / 1000
        }
        playLyric(currentTime.value)
      }
    } else {
      pauseMusic()
      if (audioRefVal) {
        audioRefVal.pause()
      }
    }
  }
)
// useLyric 播放歌词hook
const {
  currentLyric,
  currentLineText,
  currentLineNum,
  isTouchMove,
  showTimeLine,
  currentScrollLyricIndex,
  playLyric,
  pauseLyric,
  touchstart,
  touchmove,
  touchend,
  scrollHandle
} = useLyric(showCdWrapper, lyricContainerRef, lyricScrollRef, canPlay, currentTime)
watch(showCdWrapper, async (newVal) => {
  await nextTick()
  if (!newVal) {
    lyricScrollRef.value?.refresh()
    const eles = document.querySelectorAll('.lyric-wrapper .lyric-item')
    const line = currentLineNum.value
    const lineEl = eles[line]
    lineEl && lyricScrollRef.value?.scrollToElement(lineEl as HTMLElement)
  }
})
const swipeRef = ref<SwipeInstance>()
// swiper切换事件
function swiperChange(index: number) {
  if (!playerStore.playing) {
    playerStore.playing = true
  }
  playerStore.currentIndex = playerStore.playlist.findIndex(
    (song) => song.id === playerStore.sequenceList[index].id
  )
}
// swiper滚动到对应的位置
function swiperTo() {
  const index = playerStore.sequenceList.findIndex((song) => song.id === currentSong.value?.id)
  index > -1 && swipeRef.value?.swipeTo(index)
}
// 播放音乐
function playMusic() {
  canPlay.value = true
  const audioRefVal = audioRef.value
  if (!audioRefVal) {
    return
  }
  pauseLyric()
  if (playerStore.playing) {
    audioRefVal.play()
    playLyric(currentTime.value)
  } else {
    audioRefVal.pause()
    pauseLyric()
  }
}
function durationchange() {
  if (canPlay.value) {
    return
  }
  playMusic()
}
// 播放暂停,可能是用户手动暂停了音乐播放,也有可能受到外界音频干扰导致浏览器播放暂停了
function pause() {
  playerStore.playing = false
}
function playError(event: Event) {
  console.log(event, '音乐播放error')
}
// 暂停音乐
function pauseMusic() {
  const audioRefVal = audioRef.value
  if (!audioRefVal) {
    return
  }
  audioRefVal.pause()
}
// 切换到上一首歌曲
function prevSong() {
  const length = playerStore.playlist.length
  if (length === 1) {
    showToast('没有更多歌曲')
    return
  }
  if (!canPlay.value) {
    return
  }
  playerStore.currentIndex--
  if (playerStore.currentIndex < 0) {
    playerStore.currentIndex = length - 1
  }
}
// 切换到下一首歌曲
function nextSong() {
  const length = playerStore.playlist.length
  if (length === 1) {
    showToast('没有更多歌曲')
    return
  }
  if (!canPlay.value) {
    return
  }
  playerStore.currentIndex++
  if (playerStore.currentIndex === playerStore.playlist.length) {
    playerStore.currentIndex = 0
  }
}
// 歌曲自然播放结束
// 如果给audio标签设置loop为true的话,会导致ended事件不执行,我们可以把currentTime设置为0,进行重新播放
function playEnd() {
  // 判断是不是单曲循环
  if (playerStore.playMode === PLAY_MODE.LOOP) {
    currentTime.value = 0
    if (!playerStore.playing) {
      playerStore.playing = true
    }
  } else {
    if (playerStore.playlist.length === 1) {
      currentTime.value = 0
      if (!playerStore.playing) {
        playerStore.playing = true
      }
    } else {
      nextSong()
    }
  }
}
// 音乐播放时长发生变化
function timeupdate(event: Event) {
  if (progressRef.value?.touchMove) {
    return
  }
  let currentTimeValue = (event.target as HTMLAudioElement).currentTime
  currentTime.value = currentTimeValue * 1000
}
// 进度条某一位置
function updateCurrentTime(value: number) {
  currentTime.value = value
  if (progressRef.value?.touchMove) {
    return
  }
  // 如果不是播放状态,就进行播放
  const audioRefVal = audioRef.value
  if (audioRefVal) {
    // audio 的currentTime是以秒为单位的, 我们定义的currentTime是以毫秒为单位的,所以这里要除以1000
    audioRefVal.currentTime = value / 1000
  }
}
function showCdWrapperHandle(event: MouseEvent) {
  const className = (event.target as HTMLElement).className
  const index = (event.target as HTMLElement).dataset.index
  isTouchMove.value = false
  if (className === 'lyric-wrapper') {
    showCdWrapper.value = true
  } else {
    if (typeof index !== 'undefined' && Number(index) === currentScrollLyricIndex.value) {
      let time = 0
      if (typeof currentLyric.value !== 'undefined') {
        time = currentLyric.value.lines[currentScrollLyricIndex.value].time
        const eles = document.querySelectorAll('.lyric-wrapper .lyric-item')
        const lineEl = eles[currentScrollLyricIndex.value]
        lineEl && lyricScrollRef.value?.scrollToElement(lineEl as HTMLElement)
      }
      const audioRefVal = audioRef.value
      if (audioRefVal && !isTouchMove.value) {
        audioRefVal.currentTime = Number(time) / 1000
        currentTime.value = time
        playMusic()
        if (!playerStore.playing) {
          playerStore.playing = true
        }
      }
    } else {
      showCdWrapper.value = true
    }
  }
}
function playToTime() {
  let time = 0
  const audioRefVal = audioRef.value
  if (typeof currentLyric.value !== 'undefined') {
    time = currentLyric.value.lines[currentScrollLyricIndex.value].time
    if (audioRefVal && isTouchMove.value) {
      audioRefVal.currentTime = Number(time) / 1000
      currentTime.value = time
      playMusic()
      if (!playerStore.playing) {
        playerStore.playing = true
      }
      const eles = document.querySelectorAll('.lyric-wrapper .lyric-item')
      const lineEl = eles[currentScrollLyricIndex.value]
      lineEl && lyricScrollRef.value?.scrollToElement(lineEl as HTMLElement)
    }
  }
}
const touchs: {
  pageXStart: number
  pageXMove: number
} = reactive({
  pageXStart: 0,
  pageXMove: 0
})
const OFFSET = 150
const currentSongName = computed<string>(() => {
  if (
    touchs.pageXStart > 0 &&
    touchs.pageXMove > 0 &&
    Math.abs(touchs.pageXMove - touchs.pageXStart) >= OFFSET
  ) {
    let index = playerStore.currentIndex
    if (touchs.pageXMove - touchs.pageXStart < 0) {
      index++
      if (index === playerStore.sequenceList.length) {
        index = 0
      }
    } else {
      index--
      if (index < 0) {
        index = playerStore.sequenceList.length - 1
      }
    }
    return playerStore.sequenceList[index].name
  } else {
    return currentSong.value?.name || ''
  }
})
const singerStr = computed<string>(() => {
  if (
    touchs.pageXStart > 0 &&
    touchs.pageXMove > 0 &&
    Math.abs(touchs.pageXMove - touchs.pageXStart) >= OFFSET
  ) {
    let index = playerStore.currentIndex
    if (touchs.pageXMove - touchs.pageXStart < 0) {
      index++
      if (index === playerStore.sequenceList.length) {
        index = 0
      }
    } else {
      index--
      if (index < 0) {
        index = playerStore.sequenceList.length - 1
      }
    }
    return playerStore.sequenceList[index].ar.map(({ name }) => name).join('/')
  } else {
    if (typeof currentSong.value === 'undefined') {
      return ''
    }
    return currentSong.value?.ar.map(({ name }) => name).join('/')
  }
})
function swiperClick() {
  showCdWrapper.value = false
}
function cdWrapperTouchStart(event: TouchEvent) {
  touchs.pageXStart = 0
  touchs.pageXMove = 0
  touchs.pageXStart = event.touches[0].pageX
}
function cdWrapperTouchMove(event: TouchEvent) {
  touchs.pageXMove = event.touches[0].pageX
}
function cdWrapperTouchEnd() {
  touchs.pageXStart = 0
  touchs.pageXMove = 0
}
// playlist删除一首歌曲后滚动到对应的位置
function slideTo() {
  swipeRef.value?.swipeTo(playerStore.currentIndex)
}
//  用户点击了歌手名称
async function singerClick() {
  return
  // console.log(currentSong.value, 'currentSong.value')
  // const currentSongVal = currentSong.value
  // if (typeof currentSongVal === 'undefined') {
  //   return
  // }
  // // 该歌曲只有一个歌手
  // if (currentSongVal.ar.length === 1) {
  //   const { id, name } = currentSongVal.ar[0]
  //   loading.value = true
  //   const { songs } = await getSingerSongs(id)
  //   const ids = songs.map(({ id }) => id)
  //   const { data: urls } = await getSongUrl(ids)
  //   // 根据歌曲id获取到对应的url播放地址
  //   processSongUrl(songs, urls)
  //   // 处理歌曲的背景图
  //   const { songs: data } = await getSongDetail(ids)
  //   processSongPic(songs, data)
  //   songList.value = songs
  //   singerName.value = name
  //   singerPic.value = currentSongVal.al.picUrl
  //   sessionStorage.setItem(__PIC_KEY__, currentSongVal.al.picUrl)
  //   sessionStorage.setItem(__TITLE_KEY__, name)
  //   loading.value = false
  //   showMusicListCom.value = true
  //   await nextTick()
  //   ;(document.querySelector('#play-music-list-wrapper')! as HTMLElement).style.zIndex = '155'
  // } else {
  //   // 该歌曲只有对应有多个歌手
  // }
}
</script>

<template>
  <transition name="popup">
    <div v-show="playerStore.fullScreen" class="player" @click.stop>
      <div class="background">
        <img :src="currentSong?.al.picUrl" alt="" />
      </div>
      <header class="header">
        <span class="icon" @click.stop="playerStore.fullScreen = false">
          <i class="iconfont icon-back" />
        </span>
        <header class="title">
          <vue3-marquee v-if="isExceed">
            <span class="text">{{ currentSongName }}</span>
          </vue3-marquee>
          <span v-else class="text">{{ currentSongName }}</span>
        </header>
      </header>
      <p class="singer-name" @click.stop="singerClick">{{ singerStr }}</p>
      <section v-show="showCdWrapper" :style="{ height: px2vmin(middleHeight) }" class="midden">
        <section
          class="cd-wrapper"
          @touchstart.stop="cdWrapperTouchStart"
          @touchmove.stop="cdWrapperTouchMove"
          @touchend.stop="cdWrapperTouchEnd"
        >
          <van-swipe
            ref="swipeRef"
            :show-indicators="false"
            :stop-propagation="false"
            @change="swiperChange"
          >
            <van-swipe-item
              v-for="song in playerStore.sequenceList"
              :key="song.id"
              @click="swiperClick"
            >
              <div class="cd">
                <img
                  :class="playerStore.playing && song.id === currentSong?.id ? 'turn' : ''"
                  class="cd-pic"
                  :src="song?.al.picUrl"
                  alt=""
                /></div
            ></van-swipe-item>
          </van-swipe>
        </section>
        <p class="current-lyric">{{ currentLineText }}</p>
      </section>
      <section
        v-show="!showCdWrapper"
        :style="{ height: px2vmin(middleHeight) }"
        class="lyric-wrapper"
        @click.stop="showCdWrapperHandle"
      >
        <div v-show="showTimeLine" class="current-scroll-lyric" @click.stop="playToTime">
          <i class="iconfont2 icon-bofang" />
          <span class="line" />
          <span class="time">
            {{
              currentLyric &&
              moment(currentLyric.lines[currentScrollLyricIndex]?.time || 0).format('mm:ss')
            }}</span
          >
        </div>
        <scroll
          ref="lyricScrollRef"
          :bounce="false"
          :height="30"
          :probe-type="2"
          @scroll="scrollHandle"
        >
          <ul
            ref="lyricContainerRef"
            @touchstart="touchstart"
            @touchmove="touchmove"
            @touchend="touchend"
          >
            <template v-if="currentLyric">
              <li
                v-for="(line, index) in currentLyric.lines"
                :key="index"
                :class="[
                  index === currentLineNum ? 'current' : '',
                  currentScrollLyricIndex === index && isTouchMove
                    ? 'current-scroll-lyric-color'
                    : ''
                ]"
                :data-time="line.time"
                :data-index="index"
                class="lyric-item"
              >
                {{ line.text }}
              </li>
            </template>
          </ul>
        </scroll>
      </section>
      <my-progress
        ref="progressRef"
        v-model:slider-value="sliderValue"
        :current-time="currentTime"
        :duration="currentSong?.dt || 0"
        :play-lyric="playLyric"
        :pause-lyric="pauseLyric"
        @update:current-time="updateCurrentTime"
      />
      <play-controller
        :prev-song="prevSong"
        :next-song="nextSong"
        :current-song="currentSong"
        :can-play="canPlay"
      />
    </div>
  </transition>
  <!--HTML5音乐播放器-->
  <audio
    ref="audioRef"
    @canplay="playMusic"
    @durationchange="durationchange"
    @pause="pause"
    @error="playError"
    @timeupdate="timeupdate"
    @ended="playEnd"
  />
  <!--迷你播放器-->
  <mini-player v-model:showPlayList="showPlayList" :slider-value="sliderValue" />
  <playlist v-model:showPlayList="showPlayList" @slide-to="slideTo" />
  <transition name="slide">
    <div v-if="showMusicListCom" id="play-music-list-wrapper" class="music-list-wrapper">
      <music-list
        v-model:show-music-list-com="showMusicListCom"
        :song-list="songList"
        :title="singerName"
        :pic="singerPic"
        :loading="loading"
        :show-play-list="showPlayList"
        :slider-value="sliderValue"
      />
    </div>
  </transition>
</template>

<style scoped lang="scss">
.player {
  position: fixed;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  z-index: 150;
  background: $color-background;
  .background {
    position: absolute;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    z-index: -1;
    opacity: 0.6;
    filter: blur(20px);
    img {
      width: 100%;
      height: 100%;
    }
  }
  .header {
    display: flex;
    align-items: center;
    height: 30px;
    .icon {
      display: flex;
      align-items: center;
      justify-content: center;
      width: 40px;
      color: $color-theme;
      .icon-back {
        display: inline-block;
        transform: rotate(-90deg);
        font-size: $font-size-large;
      }
    }
    .title {
      box-sizing: border-box;
      padding-right: 40px;
      flex: 1;
      font-size: $font-size-large;
      text-align: center;
      height: 30px;
      line-height: 30px;
      overflow: hidden;
      white-space: nowrap;
      span {
        display: inline-block;
      }
    }
  }
  .singer-name {
    padding-bottom: 10px;
    text-align: center;
    line-height: 20px;
  }
  .midden {
    .cd-wrapper {
      box-sizing: border-box;
      padding: 40px 0;
      .cd {
        position: relative;
        height: 320px;
        .cd-pic {
          box-sizing: border-box;
          position: absolute;
          left: 50%;
          margin-left: -160px;
          top: 0;
          width: 320px;
          height: 320px;
          border-radius: 50%;
          border: 10px solid $color-dialog-background;
        }
      }
    }
    .current-lyric {
      padding: 20px 40px;
      text-align: center;
      color: $color-theme;
      font-size: $font-size-small;
    }
  }
  .lyric-wrapper {
    position: relative;
    box-sizing: border-box;
    padding: 120px 40px 0;
    height: 414px;
    overflow: hidden;
    :deep(.lyricLine-0-1-2) {
      font-size: $font-size-large;
    }
    .current-scroll-lyric {
      box-sizing: border-box;
      padding: 0 10px 10px;
      display: flex;
      align-items: center;
      position: absolute;
      top: 120px;
      left: 0;
      width: 100%;
      line-height: 20px;
      font-size: $font-size-small;
      .line {
        margin: 0 6px;
        flex: 1;
        height: 0.5px;
        background-color: $color-text-l;
      }
    }
    ul {
      box-sizing: border-box;
      .lyric-item {
        padding-bottom: 10px;
        line-height: 20px;
        text-align: center;
        font-size: $font-size-small;
        color: #ffffff;
        &.current {
          color: $color-theme !important;
        }
        &.current-scroll-lyric-color {
          color: $color-sub-theme;
        }
      }
    }
  }
}
.music-list-wrapper {
  position: fixed;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  z-index: 155;
  background-color: $color-background;
}
</style>
